package gant.ext

import gant.Gant
import gant.tools.ClassUtils
import org.codehaus.gant.GantBinding
import org.slf4j.LoggerFactory
import ch.qos.logback.classic.Level

/**
 * Created by IntelliJ IDEA.
 * User: tbarker
 * Date: 4/4/12
 * Time: 1:53 PM
 */
class GantActivator {

    Script script
    Binding binding
    Gant gant
    boolean gantIsBeingUsed = false
    private static boolean slf4jHasBeenConfigured = false
    def static final logbackResources = ["logback.xml", "logback-test.xml", "logback.groovy"]
    def static final LOGBACK_ROOT_LOGGER = "ROOT"


    def static activateGant(Script script) {
        new GantActivator(script: script).with {
            addBindingToScript()
            addExecuteTargets()
            overrideIncludeTargets()
            setUpSlf4j()
        }
    }

    /**
     * slf4j is only setup if an instance of org.slf4j.impl.StaticLoggerBinder is not available on the classpath
     *
     */
    def setUpSlf4j() {
        if (!slf4jHasBeenConfigured) {
            if(logbackIsOnTheClassPath()) {
                if (logbackIsNotConfigured()) {
                    setupLogBack()
                }
            }
        }

        binding.log = LoggerFactory.getLogger("gant.ext")
        slf4jHasBeenConfigured = true
    }

    def setupLogBack() {
        def logger = LoggerFactory.getLogger("ROOT")
        logger.setLevel(Level.INFO)
        binding.setLoggingLevel = {level ->
            logger.setLevel(level)
        }
    }

    def static logbackIsNotConfigured() {
        for(def resource : logbackResources) {
            if(resourceIsOnClassPath(resource)) {
                return false
            }
        }

        return true
    }

    def static resourceIsOnClassPath(String resourceName) {
        return ClassUtils.defaultClassLoader.getResource(resourceName) != null
    }

    def static logbackIsOnTheClassPath() {
        return classExists("ch.qos.logback.classic.Logger")
    }

    def static classExists(String className) {
        try {
            ClassUtils.defaultClassLoader.loadClass(className)
            return true
        } catch (Exception e) {
            return false
        }
    }

    /**
     * uses the improved includeTargets
     */
    def overrideIncludeTargets() {
        getBinding().forcedSettingOfVariable('includeTargets', new IncludeTargetsWithStringAsClassName(this.binding))
    }

    Binding getBinding() {
        if (binding) {
            return binding
        }

        if (script.binding instanceof GantBinding) {
            gantIsBeingUsed = true
            binding = script.binding
        } else {
            binding = new GantBinding(script.binding)
        }
    }

    Gant getGant() {
        if (gant) {
            return gant
        }

        gant = new Gant(getBinding())
    }

    void addBindingToScript() {
        def bindingToUse = getBinding()
        script.binding = bindingToUse
    }

    void addExecuteTargets() {
        if (!gantIsBeingUsed) {
            getBinding().executeTargets = {List<String> targets = [] ->
                getScript().metaClass.run = {->
                    //do nothing, already running
                }

                getGant().executeTargets('dispatch', targets)
            }
        }
    }

}
